using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;

namespace GoodStuff
{
    /// <summary>
    /// Implements a UI control for a Rectangle structure out of four numeric up/down controls
    /// Bindings are: { Rectangle value, Rectangle minimum bounding rectangle, maximum bounding rectangle, 
    /// string[] display text}
    /// </summary>
     public class GoodRectangleControl : GoodControlBase
     {
         GoodConvertibleVariable<int>[] _variables;
         GoodNumericUpDown[] _controls;
         bool _updating;
         GoodVariable<Rectangle> _variable, _minimum, _maximum;

         /// <summary>
         /// called when the variable changes
         /// if _updating is false, call was initiated from outside the control
         /// </summary>
         /// <param name="sender">Variable that changed</param>
         /// <param name="args">Empty EventArgs</param>
         protected override void OnVariableChanged(object sender, EventArgs args)
         {
             if (!_updating)
             {
                _updating = true;
                Rectangle r = _variable.Value;
                 _variables[0].Value = r.X;
                 _variables[1].Value = r.Width;
                 _variables[2].Value = r.Y;
                 _variables[3].Value = r.Height;
                 _updating = false;
              }
         }

         /// <summary>
         /// called when any of the control changes -- do not call directly
         /// </summary>
         /// <param name="sender">Control that changed</param>
         /// <param name="args">Empty EventArgs</param>
         protected void OnControlChanged(object sender, EventArgs args)
         {
             if (!_updating)
             {
                 Trace.WriteLine("GoodRectangle " + _variable.InstanceName + " changed in UI");
                 _updating = true;
                 Rectangle newRectangle = new Rectangle(
                     (int)_variables[0].Value,
                     (int)_variables[2].Value,
                     (int)_variables[1].Value,
                     (int)_variables[3].Value);

                 (_variable as GoodVariable<Rectangle>).Value = newRectangle;

                 // check to see if the value of the variable changed after validation
                 Rectangle r = (_variable as GoodVariable<Rectangle>).Value;
                 if (r != newRectangle)
                 {
                     _variables[0].Value = r.X;
                     _variables[2].Value = r.Left;
                     _variables[1].Value = r.Y;
                     _variables[3].Value = r.Right;
                 }

                 _updating = false;
             }
         }


         public override void Initialize()
         {
             base.Initialize();

             _controls = new GoodNumericUpDown[4];
             _variables = new GoodConvertibleVariable<int>[4];

             _updating = true;
             _variable = (GoodVariable<Rectangle>)ParameterVariable("Variable") ;
             _variable.ValueChanged += OnVariableChanged;

             Trace.WriteLine("Initializing GoodRectangleControl " + _variable.InstanceName);

             // create the GroupBox that will hold the four NumericUpDown controls
             GroupBox gb = new GroupBox();
             _control = gb;
             gb.Margin = new Padding(3, 15, 3, 3);
             gb.Text = ParameterText("Text");

             // create X, Y, width, and height variables and controls
             string[] parameterName = new string[4] { "XText", "WidthText", "YText", "HeightText" };
             string[] defaultText = new string[4] { "X", "Width", "Y", "Height" };
             for (int i = 0; i < 4; ++i)
             {
                 _controls[i] = new GoodNumericUpDown();
                 _variables[i] = new GoodConvertibleVariable<int>();

                 _variables[i].InstanceName = defaultText[i];
                 _variables[i].ValueChanged += OnControlChanged;

                 Dictionary<string, object> parameters = new Dictionary<string, object>();
                 string controlName = ParameterText(parameterName[i]);
                 if(controlName == null)
                     controlName = defaultText[i];
                 parameters.Add("Text", controlName);
                 parameters.Add("Variable", _variables[i]);
                 _controls[i].ParameterList = parameters;
                 _controls[i].Initialize();
                gb.Controls.Add(_controls[i].Control);
             }

             // initialize the internal Rectangle components to match the value of the variable
             _variables[0].Value = _variable.Value.X;
             _variables[1].Value = _variable.Value.Width;
             _variables[2].Value = _variable.Value.Y;
             _variables[3].Value = _variable.Value.Height;
             _updating = false;
             
             // lay out the control
             Size t = new Size(0, 0);
             int w = gb.Margin.Left + Math.Max(_controls[0].Control.Size.Width, _controls[2].Control.Size.Width);
             int h = gb.Margin.Top + Math.Max(_controls[0].Control.Size.Height, _controls[1].Control.Size.Height);
             _controls[0].Control.Location = new Point(gb.Margin.Left, gb.Margin.Top);
             _controls[1].Control.Location = new Point(
                 w + Math.Max(0, _controls[3].Control.Width -_controls[1].Control.Width),
                 gb.Margin.Top);
             _controls[2].Control.Location = new Point(gb.Margin.Left, h);
             _controls[3].Control.Location = new Point(
                 w + Math.Max(0, _controls[1].Control.Width - _controls[3].Control.Width),  
                 h);
             w += Math.Max(_controls[1].Control.Size.Width, _controls[3].Control.Size.Width) + gb.Margin.Right;
             h += Math.Max(_controls[2].Control.Size.Height, _controls[3].Control.Size.Height) + gb.Margin.Bottom;
             gb.Size = new Size(w, h);

             // set up ValueChanged handler
             _variable.ValueChanged += OnVariableChanged;
         }
     }

}
